package com.fowo.api.sys.performance.aop;


import com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator;
import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
import com.fowo.api.sys.performance.PerformanceLogService;
import com.fowo.api.sys.performance.model.PerformanceLogModel;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.springframework.util.ClassUtils;

import java.lang.reflect.Method;
import java.util.Date;

public class PerformanceLogInterceptor implements MethodInterceptor {
    private static final IdentifierGenerator idGenerator = new DefaultIdentifierGenerator();
    private final PerformanceLogService performanceLogService;

    public PerformanceLogInterceptor(PerformanceLogService performanceLogService) {
        this.performanceLogService = performanceLogService;
    }

    @Nullable
    @Override
    public Object invoke(@NotNull MethodInvocation invocation) throws Throwable {
        Date startTime = new Date();
        Long logId = (Long) idGenerator.nextId(null);
        int status = PerformanceLogModel.STATUS_RUNNING;
        String invokeTarget = getTargetClass(invocation.getMethod().getDeclaringClass()).getName() + ":" + invocation.getMethod().getName();
        try {
            Object o = invocation.proceed();
            status = PerformanceLogModel.STATUS_SUCCESS;
            return o;
        }
        catch (Throwable throwable) {
            status = PerformanceLogModel.STATUS_FAIL;
            throw throwable;
        }
        finally {
            Date endTime = new Date();
            PerformanceLogModel log = new PerformanceLogModel();
            log.setId(logId);
            log.setInvokeTarget(invokeTarget);
            log.setStartTime(startTime);
            log.setEndTime(endTime);
            log.setStatus(status);
            performanceLogService.write(log);
        }
    }

    private Class<?> getTargetClass(Class<?> clz) {
        while (true) {
            Class<?> uClz = ClassUtils.getUserClass(clz);
            if (uClz == clz) {
                return uClz;
            }
            clz = uClz;
        }
    }
}
